package cn.youqu.happy.module.youqu.service.arrangeEdit;

import cn.youqu.happy.framework.common.pojo.PageResult;
import cn.youqu.happy.module.youqu.controller.admin.arrangeEdit.vo.ArrangeEditCreateReqVO;
import cn.youqu.happy.module.youqu.controller.admin.arrangeEdit.vo.ArrangeEditExportReqVO;
import cn.youqu.happy.module.youqu.controller.admin.arrangeEdit.vo.ArrangeEditPageReqVO;
import cn.youqu.happy.module.youqu.controller.admin.arrangeEdit.vo.ArrangeEditUpdateReqVO;
import cn.youqu.happy.module.youqu.controller.admin.userArrange.vo.UserArrangeUpdateReqVO;
import cn.youqu.happy.module.youqu.controller.app.arrangeEdit.vo.AppArrangeEditCreateReqVO;
import cn.youqu.happy.module.youqu.controller.app.arrangeEdit.vo.AppArrangeEditStateReqVO;
import cn.youqu.happy.module.youqu.convert.arrangeEdit.ArrangeEditConvert;
import cn.youqu.happy.module.youqu.convert.userArrange.UserArrangeConvert;
import cn.youqu.happy.module.youqu.dal.dataobject.arrangeEdit.ArrangeEditDO;
import cn.youqu.happy.module.youqu.dal.dataobject.userArrange.UserArrangeDO;
import cn.youqu.happy.module.youqu.dal.mysql.arrangeEdit.ArrangeEditMapper;
import cn.youqu.happy.module.youqu.enums.arrangeEdit.ArrangeEditApplyStatusEnum;
import cn.youqu.happy.module.youqu.enums.arrangeEdit.ArrangeEditApplyTypeEnum;
import cn.youqu.happy.module.youqu.enums.userArrange.UserArrangeStatusEnum;
import cn.youqu.happy.module.youqu.service.userArrange.UserArrangeService;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.youqu.happy.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.youqu.happy.module.youqu.enums.ErrorCodeConstants.*;

/**
 * 计划申请修改 Service 实现类
 *
 * @author 王其岩 20112001045
 */
@Service
@Validated
public class ArrangeEditServiceImpl implements ArrangeEditService {

    @Resource
    private ArrangeEditMapper arrangeEditMapper;

    @Resource
    @Lazy
    private UserArrangeService userArrangeService;

    @Override
    public Integer createArrangeEdit(ArrangeEditCreateReqVO createReqVO) {
        // 插入
        ArrangeEditDO arrangeEdit = ArrangeEditConvert.INSTANCE.convert(createReqVO);
        arrangeEditMapper.insert(arrangeEdit);
        // 返回
        return arrangeEdit.getId();
    }

    @Override
    public void updateArrangeEdit(ArrangeEditUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateArrangeEditExists(updateReqVO.getId());
        // 更新
        ArrangeEditDO updateObj = ArrangeEditConvert.INSTANCE.convert(updateReqVO);
        arrangeEditMapper.updateById(updateObj);
    }

    @Override
    public void updateArrangeEdit(ArrangeEditUpdateReqVO updateReqVO, Long uid) {
        ArrangeEditDO arrangeEditDO = arrangeEditMapper.findOneByIdAndApplyUid(updateReqVO.getId(), uid);
        if (arrangeEditDO == null) {
            throw exception(ARRANGE_EDIT_NOT_EXISTS);
        }
        arrangeEditMapper.updateById(arrangeEditDO);
    }


    @Override
    public void deleteArrangeEdit(Integer id) {
        // 校验存在
        this.validateArrangeEditExists(id);
        // 删除
        arrangeEditMapper.deleteById(id);
    }

    public boolean cancelArrangeEdit(Integer id, String reason, Long applyUid) {
        this.validateArrangeEditExists(id, applyUid);
        if (reason == null) {
            reason = "用户主动取消申请";
        }
        int i = arrangeEditMapper.updateApplyStatusAndRemarkById(ArrangeEditApplyStatusEnum.APPLY_CANCEL.getStatus(), reason, id);
        return i > 0;
    }

    private void validateArrangeEditExists(Integer id) {
        if (arrangeEditMapper.selectById(id) == null) {
            throw exception(ARRANGE_EDIT_NOT_EXISTS);
        }
    }

    private void validateArrangeEditExists(Integer id, Long applyUid) {
        if (arrangeEditMapper.findOneByIdAndApplyUid(id, applyUid) == null) {
            throw exception(ARRANGE_EDIT_NOT_EXISTS);
        }
    }

    @Override
    public boolean validateUserOwnArrangeEdit(Integer id, Long partner) {
        ArrangeEditDO arrangeEditDO = arrangeEditMapper.selectById(id);
        if (arrangeEditDO == null) {
            throw exception(USER_ARRANGE_NOT_EXISTS);
        } else {
            if (partner.equals(arrangeEditDO.getApplyUid())) {
                return true;
            }
            if (arrangeEditDO.getArrangeId() == null) {
                throw exception(USER_ARRANGE_NOT_EXISTS);
            }
            UserArrangeDO userArrange = userArrangeService.getUserArrange(arrangeEditDO.getArrangeId());
            return userArrangeService.validateUserOwnUserArrange(userArrange.getId(), partner);
        }
    }

    private void validateAlreadyStateArrangeEdit(ArrangeEditDO arrangeEditDO, Long uid) {
        List<String> agreeUser = convertPartners(arrangeEditDO.getAgreeIds());
        List<String> refuseUser = convertPartners(arrangeEditDO.getRefuseIds());


        if (agreeUser.stream().anyMatch(item -> String.valueOf(uid).equals(item)) ||
                refuseUser.stream().anyMatch(item -> String.valueOf(uid).equals(item))
        ) {
            throw exception(ARRANGE_EDIT_ALREADY_STATE);
        }
    }

    /**
     * 将逗号分割的转为数组 避免空指针异常
     *
     * @param partners
     * @return
     */
    private List<String> convertPartners(String partners) {
        if (partners != null) {
            return new ArrayList<>(Arrays.asList(partners.split(",")));
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public boolean stateArrangeEdit(AppArrangeEditStateReqVO stateReqVO, Long uid) {
        //1. 校验是否可表态
        this.validateUserOwnArrangeEdit(stateReqVO.getId(), uid);
        ArrangeEditDO arrangeEditDO = arrangeEditMapper.selectById(stateReqVO.getId());
        //2. 校验是否在申请中
        if (arrangeEditDO.getApplyStatus() != ArrangeEditApplyStatusEnum.APPLY_ING.getStatus()) {
            throw exception(ARRANGE_EDIT_ALREADY_END);
        }
        //判断是否已经表态
        this.validateAlreadyStateArrangeEdit(arrangeEditDO, uid);


        if (stateReqVO.isAgree()) {
            String agreeIds = arrangeEditDO.getAgreeIds();
            List<String> partnerArr = convertPartners(agreeIds);
            if (partnerArr.stream().anyMatch(item -> String.valueOf(uid).equals(item))) {
                throw exception(ARRANGE_EDIT_ALREADY_AGREE);
            } else {
                partnerArr.add(String.valueOf(uid));
                arrangeEditDO.setAgreeIds(String.join(",", partnerArr));
            }
        } else {
            String refuseIds = arrangeEditDO.getRefuseIds();
            List<String> partnerArr = convertPartners(refuseIds);
            if (partnerArr.stream().anyMatch(item -> String.valueOf(uid).equals(item))) {
                throw exception(ARRANGE_EDIT_ALREADY_DISAGREE);
            } else {
                partnerArr.add(String.valueOf(uid));
                arrangeEditDO.setRefuseIds(String.join(",", partnerArr));
            }
        }
        int i = arrangeEditMapper.updateById(arrangeEditDO);
        //判断是否全部同意 然后处理更改
        this.autoUpdateEditStatus(arrangeEditDO.getId());
        return i > 0;
    }

    /**
     * 自动更新申请表状态
     *
     * @param arrangeEditId
     */
    @Async
    public void autoUpdateEditStatus(Integer arrangeEditId) {
        ArrangeEditDO arrangeEditDO = arrangeEditMapper.selectById(arrangeEditId);
        if (arrangeEditDO != null) {
            if (arrangeEditDO.getApplyStatus() == ArrangeEditApplyStatusEnum.APPLY_ING.getStatus()) {
                Long agreeCount = (long) convertPartners(arrangeEditDO.getAgreeIds()).size();
                Long refuseCount = (long) convertPartners(arrangeEditDO.getRefuseIds()).size();


                Integer arrangeId = arrangeEditDO.getArrangeId();
                UserArrangeDO userArrange = userArrangeService.getUserArrange(arrangeId);

                Long total = Long.valueOf(convertPartners(userArrange.getPartners()).size());
                if (total <= agreeCount) {//全部同意
                    //更新编辑状态
                    arrangeEditMapper.updateApplyStatusAndRemarkById(ArrangeEditApplyStatusEnum.APPLY_SUCCESS.getStatus(), "所有人同意修改", arrangeEditId);
                    //更新活动安排
                    if (arrangeEditDO.getApplyType() == ArrangeEditApplyTypeEnum.CANCEL_ARRANGE.getType()) {
                        userArrange.setArrangeStatus(UserArrangeStatusEnum.ARRANGE_CANCEL.getStatus());
                    } else if (arrangeEditDO.getApplyType() == ArrangeEditApplyTypeEnum.MODIFY_ARRANGE.getType()) {
                        Date modifyTime = arrangeEditDO.getModifyTime();
                        userArrange.setStartDate(modifyTime);
                    }
                    UserArrangeUpdateReqVO convert1 = UserArrangeConvert.INSTANCE.convert1(userArrange);
                    userArrangeService.updateUserArrange(convert1);
                } else if (agreeCount + refuseCount >= total) {//所有人表态完毕
                    //关闭申请
                    arrangeEditMapper.updateApplyStatusAndRemarkById(ArrangeEditApplyStatusEnum.APPLY_FAIL.getStatus(), "未取得所有人同意", arrangeEditId);
                }
            }
        }
    }

    @Override
    public Integer createArrangeEdit(AppArrangeEditCreateReqVO createReqVO, Long loginUserId) {
        UserArrangeDO userArrange = userArrangeService.getUserArrange(createReqVO.getArrangeId());
        if (userArrange == null) {
            throw exception(USER_ARRANGE_NOT_EXISTS);
        }
        //判断是否可以编辑
        this.canCreateArrangeEdit(createReqVO.getArrangeId(), loginUserId);

        //判断是否已经有在申请中的
        if (alreadyHaveArrangeEdit(createReqVO.getArrangeId())) {
            throw exception(ARRANGE_EDIT_ALREADY_EXIST);
        }
        if (createReqVO.getApplyType() == ArrangeEditApplyTypeEnum.MODIFY_ARRANGE.getType()) {

            if (createReqVO.getModifyTime() == null) {
                throw exception(ARRANGE_EDIT_MODIFY_TIME_CON_NOT_NULL);
            } else {
                //校验时间是否可用
                if (createReqVO.getModifyTime().compareTo(new Date()) <= 0) {
                    throw exception(ARRANGE_EDIT_MODIFY_TIME_NOT_AVAILABLE);
                }
            }
        }
        ArrangeEditDO convert = ArrangeEditConvert.INSTANCE.convert(createReqVO);
        convert.setApplyUid(loginUserId);
        convert.setApplyStatus(ArrangeEditApplyStatusEnum.APPLY_ING.getStatus());
        arrangeEditMapper.insert(convert);
        return convert.getId();
    }

    @Override
    public boolean alreadyHaveArrangeEdit(Integer id) {
        return arrangeEditMapper.countByArrangeIdAndApplyStatus(id, ArrangeEditApplyStatusEnum.APPLY_ING.getStatus()) > 0;
    }

    @Override
    public boolean canCreateArrangeEdit(Integer arrangeId, Long uid) {
        //1.判断是否拥有此安排
        userArrangeService.validateUserOwnUserArrange(arrangeId, uid);
        //2.判断是否已存在编辑申请
        if (alreadyHaveArrangeEdit(arrangeId)) {
            throw exception(ARRANGE_EDIT_ALREADY_EXIST);
        }
        return true;
    }


    /**
     * 筛选用户拥有的活动编辑表
     *
     * @param arrangeEditDOs
     * @param uid
     * @return
     */
    private List<ArrangeEditDO> filterOwnUserArrange(List<ArrangeEditDO> arrangeEditDOs, Long uid) {
        List<Integer> collect = arrangeEditDOs.stream().map(item -> item.getArrangeId()).collect(Collectors.toList());
        List<UserArrangeDO> userArrangeList = userArrangeService.getUserArrangeList(collect);
        Map<Integer, UserArrangeDO> userArrangeDOMap = new HashMap<>();

        userArrangeList.forEach(item -> {
            userArrangeDOMap.put(item.getId(), item);
        });

        return arrangeEditDOs.stream().filter(item -> {
            UserArrangeDO userArrangeItem = userArrangeDOMap.get(item.getArrangeId());
            if (userArrangeItem != null) {
                if (uid.equals(item.getApplyUid())) {
                    return true;
                }
                List<String> partnerArr = convertPartners(userArrangeItem.getPartners());
                return partnerArr.stream().anyMatch(item1 -> String.valueOf(uid).equals(item1));
            } else {
                return false;
            }
        }).collect(Collectors.toList());
    }

    @Override
    public ArrangeEditDO getArrangeEdit(Integer id) {
        return arrangeEditMapper.selectById(id);
    }

    @Override
    public ArrangeEditDO getArrangeEdit(Integer id, Long uid) {
        this.validateUserOwnArrangeEdit(id, uid);
        return arrangeEditMapper.selectById(id);
    }

    @Override
    public List<ArrangeEditDO> getArrangeEditList(Collection<Integer> ids) {
        return arrangeEditMapper.selectBatchIds(ids);
    }

    @Override
    public List<ArrangeEditDO> getArrangeEditList(Collection<Integer> ids, Long uid) {
        List<ArrangeEditDO> arrangeEditDOS = arrangeEditMapper.selectBatchIds(ids);
        return filterOwnUserArrange(arrangeEditDOS, uid);
    }

    @Override
    public PageResult<ArrangeEditDO> getArrangeEditPage(ArrangeEditPageReqVO pageReqVO) {
        return arrangeEditMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<ArrangeEditDO> getArrangeEditPage(ArrangeEditPageReqVO pageReqVO, Long uid) {
        PageResult<ArrangeEditDO> arrangeEditDOPageResult = arrangeEditMapper.selectPage(pageReqVO);
        List<ArrangeEditDO> list = arrangeEditDOPageResult.getList();
        List<ArrangeEditDO> arrangeEditDOS = filterOwnUserArrange(list, uid);
        arrangeEditDOPageResult.setList(arrangeEditDOS);
        arrangeEditDOPageResult.setTotal(Long.valueOf(arrangeEditDOS.size()));
        return arrangeEditDOPageResult;
    }

    @Override
    public List<ArrangeEditDO> getArrangeEditList(ArrangeEditExportReqVO exportReqVO) {
        return arrangeEditMapper.selectList(exportReqVO);
    }

}
